package com.rocketmq.temp3.repository.support;

//import com.potyun.global.common.RedisUtils;
//import com.potyun.global.constant.CacheConstant;

import com.rocketmq.temp3.common.support.BeanLifecycle;
import com.rocketmq.temp3.entity.support.AppGenKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.text.MessageFormat;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 分布式全局唯一ID生成服务
 */
@Slf4j
@Component
public class AppGenKeyHandler extends BeanLifecycle implements AppGenKey {

    /**
     * 当前应用启动时在服务器上的唯一标识
     */
    private Long workerId = -1L;
    /**
     * 工作机器ID(0~31)
     */
    private String defWorkerId;
    /**
     * 工作机器名称
     */
    private String groupWorker;
    /**
     * 上次生成ID的时间截
     */
    private volatile long lastTimeStamp = -1L;
    /**
     * 毫秒内序列(10-99)
     */
    private AtomicLong sequence = new AtomicLong(100L);

    public AppGenKeyHandler(@Value("${generate.id.workerID:200}") String defWorkerId,
                            @Value("${generate.id.groupWorker:sms}") String groupWorker) {
        this.defWorkerId = defWorkerId;
        this.groupWorker = groupWorker;
    }

    @Override
    public Long getUniqueKey() {
        // 当前时间戳
        long timeStamp = System.currentTimeMillis();
        // 如果当前时间小于上一次ID生成的时间戳，说明系统时钟回退过这个时刻应当抛出异常
        if (timeStamp < this.lastTimeStamp) {
            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimeStamp - timeStamp));
        }

        // 如果是同一时间生成的，则进行毫秒内序列
        if (this.lastTimeStamp == timeStamp) {
            // 毫秒内序列溢出
            if (this.sequence.get() >= 1000) {
                // 阻塞到下一个毫秒,获得新的时间戳（以while循环的方式短暂阻塞）
                while (timeStamp <= this.lastTimeStamp) {
                    timeStamp = System.currentTimeMillis();
                }
                this.sequence.set(100L);
            }
        } else {
            this.sequence.set(100L);
        }
        this.lastTimeStamp = timeStamp;
        String genId = MessageFormat.format("{0}{1}{2}", String.valueOf(this.workerId), String.valueOf(timeStamp), String.valueOf(this.sequence.getAndIncrement()));
        return Long.valueOf(genId);
    }

    @Override
    protected void initMethod() {
//        // 生成唯一的服务器标识
//        if (this.workerId != -1L) {
//            return;
//        }
//        String uniqueServerKey = this.groupWorker + ":" + GenerateUtils.getServerIp();
//        Object workerIdFromCache = RedisUtils.getHashValue(CacheConstant.NormalRedisKey.REDIS_WORKER_ID_HASH_KEY.getKey(), uniqueServerKey);
//        if (workerIdFromCache != null) {
//            this.workerId = Long.valueOf(String.valueOf(workerIdFromCache));
//            return;
//        }
//        RedisUtils.putValueIfAbsent(CacheConstant.NormalRedisKey.REDIS_WORKER_ID_INCR_KEY.getKey(), this.defWorkerId);
//        this.workerId = RedisUtils.incrementAndGetValue(CacheConstant.NormalRedisKey.REDIS_WORKER_ID_INCR_KEY.getKey());
//        RedisUtils.putHash(CacheConstant.NormalRedisKey.REDIS_WORKER_ID_HASH_KEY.getKey(), uniqueServerKey, this.workerId);
    }

    @Override
    protected void destroyMethod() {
        // 销毁当前服务器标识
        // no no no, there are nothing to do.
        // 不要从redis中移除标识workerId的缓存，因为生产环境的服务器IP地址几乎是不可能变动的！
    }

}
